#ifndef __testpobo_xml_parser_h__
#define __testpobo_xml_parser_h__

namespace testpobo
{
    class CXmlParser:public boost::enable_shared_from_this<CXmlParser>
    {
    public:
        CXmlParser(boost::asio::io_service& ios, LoggerPtr logger):
          m_ios(ios),m_logger(logger),m_initial(false),m_downTime(0,0,5)
          {
              m_parseBuf.reserve(2048);
          }

          ~CXmlParser()
          {

          }

          void parse(const string& data)
          {
              m_ios.post(boost::bind(&CXmlParser::on_data, shared_from_this(), (data)));
          }

    private:
        ptime from_iso_extended_string(const string& inDateString) 
        { 
            // If we get passed a zero length string, then return the "not a date" value. 
            if (inDateString.empty()) 
            { 
                return not_a_date_time; 
            } 

            // Use the ISO extended input facet to interpret the string. 
            std::stringstream ss; 
            time_input_facet* input_facet = new time_input_facet(); 
            input_facet->set_iso_extended_format(); 
            ss.imbue(std::locale(ss.getloc(), input_facet)); 
            ss.str(inDateString); 
            ptime timeFromString; 
            ss >> timeFromString; 

            return timeFromString; 
        } 

        void on_data(string data)
        {
            static TLUint64 id = tlgettid();
            m_parseBuf.append(data);
            std::string::size_type pos = m_parseBuf.find("\r\n");
            std::string::size_type off = 0;
            std::string::size_type len = m_parseBuf.length();
            while(pos != std::string::npos)
            {
                std::string xmldoc(m_parseBuf.substr(off, pos - off));
                std::string::size_type timetagStart = xmldoc.find("2010");
                if(timetagStart != std::string::npos)
                {
                    std::string::size_type timetagEnd = xmldoc.find("\"", timetagStart);
                    std::string timetag(xmldoc.substr(timetagStart, timetagEnd-timetagStart));
                    try
                    {
                        ptime t(from_iso_extended_string(timetag));
                        ptime now = boost::posix_time::microsec_clock::universal_time();
                        boost::posix_time::time_duration span = now - m_localTime;
                        boost::posix_time::time_duration lag = span - (t - m_serverTime);
                        boost::posix_time::time_duration span2 = span - m_downTime;
                        
                        m_serverTime = t;
                        m_localTime = now;
                        TLInt64 millisecLag = (lag.total_microseconds()/1000);
                        if(!m_initial)
                        {
                            m_initial = true;
                        }
                        else
                        {
                            if (!span2.is_negative())
                            {
                                LOG4CXX_WARN(m_logger, boost::format("[Parser@Thread%1%] heartbeat is longger than 5 seconds.") % id);
                            }
                            /*else
                            {
                                LOG4CXX_INFO(m_logger, boost::format("[Parser@Thread%1%] heartbeat interval %2% milliseconds.") % id % span.total_milliseconds());
                            }*/
                            if ((millisecLag > 500) ||(millisecLag < -500))
                            {
                                LOG4CXX_WARN(m_logger, boost::format("[Parser@Thread%1%] localtime: %2%, servertime: %3%, lag: %4%ms") % id % 
                                    boost::posix_time::to_iso_extended_string(now) % timetag % millisecLag);
                            }
                            
                        }
                    }
                    catch (std::exception& e)
                    {
                        LOG4CXX_WARN(m_logger, boost::format("[Parser@Thread%1%] %2%") % id % e.what());
                    }
                    catch(...)
                    {
                        LOG4CXX_WARN(m_logger, boost::format("[Parser@Thread%1%] Calc lag error") % id);
                    }
                }
                //LOG4CXX_INFO(m_logger, xmldoc.c_str());
                off = pos+2;
                pos = m_parseBuf.find("\r\n", off);
            }
            m_parseBuf = m_parseBuf.substr(off, len - off);
        }

    private:
        boost::asio::io_service&            m_ios;
        string                              m_parseBuf;
        LoggerPtr                           m_logger;
        ptime                               m_serverTime;
        ptime                               m_localTime;
        bool                                m_initial;
        boost::posix_time::time_duration    m_downTime;
    };
}

#endif // __testpobo_xml_parser_h__
